package com.didd.core.common.utils;

import com.alibaba.fastjson.JSON;
import com.didd.core.common.base.Params;
import com.didd.core.common.base.ResultStatus;
import com.didd.core.common.base.RpcResponse;
import com.didd.core.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

import static com.didd.core.common.base.ResultCode.FAIL_BIZ_PARAMETER;

/**
 * RpcResponse工具类
 *
 * @author diddd
 * @Created 2020/11/5 14:13
 */
@Slf4j
public class RpcResponseUtil {

    /**
     * 调用远程服务
     *
     * @param funcDesc    接口功能描述
     * @param rpcResponse 服务响应
     * @param <T>
     * @return
     */
    public static <T> T callRpc(String funDesc, RpcResponse<T> rpcResponse) {
        return parseData(funDesc, rpcResponse, "", Boolean.FALSE);
    }

    /**
     * 调用远程服务
     *
     * @param funcDesc    接口功能描述
     * @param rpcResponse 服务响应
     * @param failMessage 失败信息
     * @param <T>
     * @return
     */
    public static <T> T callRpc(String funDesc, RpcResponse<T> rpcResponse, String failMessage) {
        return parseData(funDesc, rpcResponse, failMessage, Boolean.FALSE);
    }

    /**
     * 调用远程服务
     *
     * @param funcDesc    接口功能描述
     * @param rpcResponse 服务响应
     * @param errorCode   异常枚举
     * @param <T>
     * @return
     */
    public static <T> T callRpc(String funDesc, RpcResponse<T> rpcResponse, ResultStatus errorCode) {
        return parseData(funDesc, rpcResponse, errorCode, Boolean.FALSE);
    }

    /**
     * 解析 RpcResponse服务响应数据 ---- 默认不发钉钉消息
     *
     * @param rpcResponse dubbo服务响应
     * @param failMessage 异常信息
     * @param <T>
     * @return
     */
    public static <T> T parseData(RpcResponse<T> rpcResponse) {
        return parseData("远程服务调用", rpcResponse, "", Boolean.FALSE);
    }

    /**
     * 解析 RpcResponse服务响应数据 ---- 默认不发钉钉消息
     *
     * @param rpcResponse dubbo服务响应
     * @param failMessage 异常信息
     * @param <T>
     * @return
     */
    public static <T> T parseData(RpcResponse<T> rpcResponse, String failMessage) {
        return parseData("远程服务调用", rpcResponse, failMessage, Boolean.FALSE);
    }

    /**
     * 解析 RpcResponse服务响应数据 ---- 默认不发钉钉消息
     *
     * @param rpcResponse dubbo服务响应
     * @param errorCode   异常枚举
     * @param <T>
     * @return
     */
    public static <T> T parseData(RpcResponse<T> rpcResponse, ResultStatus errorCode) {
        return parseData("远程服务调用", rpcResponse, errorCode, Boolean.TRUE);
    }

    /**
     * 解析  RpcResponse服务响应数据
     *
     * @param funcDesc    接口功能描述
     * @param rpcResponse dubbo服务响应
     * @param errorCode   异常枚举
     * @param isWarning   是否发送钉钉告警
     * @param <T>
     * @return
     */
    public static <T> T parseData(String funcDesc, RpcResponse<T> rpcResponse, ResultStatus errorCode, Boolean isWarning) {
        if (StringUtils.isNotBlank(funcDesc)) {
            funcDesc = "[" + funcDesc + "]";
        }
        log.info(funcDesc + " 响应信息 rpcResponse:[{}]", JSON.toJSONString(rpcResponse));
        //成功
        if (null != rpcResponse && rpcResponse.hasSuccess()) {
            return rpcResponse.getData();
        }
        if (null == rpcResponse) {
            log.error(funcDesc + "-调用失败");
            if (null != errorCode) {
                throw new BizException(isWarning, errorCode);
            } else {
                throw new BizException(isWarning, funcDesc + "[失败]");
            }
        }

        //解析参数错误信息
        if (rpcResponse.getCode() == FAIL_BIZ_PARAMETER.fetchCode()) {
            RpcResponse<List<Params>> errorResponse = (RpcResponse<List<Params>>) rpcResponse;
            parseParamsError(errorResponse);
        }

        log.error(funcDesc + "服务响应失败,rpcResponse:[{}]", rpcResponse.toString());
        if (null != errorCode) {
            throw new BizException(isWarning, errorCode);
        } else {
            throw new BizException(isWarning, rpcResponse.getMessage());
        }
    }

    /**
     * 解析 RpcResponse服务响应数据
     *
     * @param funcDesc    接口功能描述
     * @param rpcResponse dubbo服务响应
     * @param failMessage 异常信息
     * @param isWarning   是否发送钉钉告警
     * @param <T>
     * @return
     */
    public static <T> T parseData(String funcDesc, RpcResponse<T> rpcResponse, String failMessage, Boolean isWarning) {
        if (StringUtils.isNotBlank(funcDesc)) {
            funcDesc = "[" + funcDesc + "]";
        }
        log.info(funcDesc + " 响应信息 rpcResponse:[{}]", JSON.toJSONString(rpcResponse));
        //成功
        if (null != rpcResponse && rpcResponse.hasSuccess()) {
            return rpcResponse.getData();
        }

        if (null == rpcResponse) {
            log.error(funcDesc + "-调用失败");
            if (StringUtils.isNotBlank(failMessage)) {
                throw new BizException(Boolean.TRUE, funcDesc + failMessage);
            } else {
                throw new BizException(Boolean.TRUE, funcDesc + "[失败]");
            }
        }

        //解析参数错误信息
        if (rpcResponse.getCode() == FAIL_BIZ_PARAMETER.fetchCode()) {
            RpcResponse<List<Params>> errorResponse = (RpcResponse<List<Params>>) rpcResponse;
            parseParamsError(errorResponse);
        }

        log.error(funcDesc + "服务响应失败,rpcResponse:[{}]", rpcResponse.toString());
        if (StringUtils.isNotBlank(failMessage)) {
            throw new BizException(isWarning, failMessage);
        } else {
            throw new BizException(isWarning, rpcResponse.getMessage());
        }
    }

    /**
     * 解析参数错误信息
     *
     * @param rpcResponse dubbo服务响应
     */
    private static void parseParamsError(RpcResponse<List<Params>> rpcResponse) {
        List<Params> paramsList = rpcResponse.getData();
        String errorStr = StringUtils.join(paramsList.stream().map(Params::getMessage).collect(Collectors.toList()), ",");
        throw new BizException(Boolean.TRUE, errorStr);
    }
}
